Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.ComponentModel
Imports System.Web.Script.Services
Imports System.Drawing
Imports System.IO


Namespace WESNet.AJAX.Controls.ImageEditor

    <WebService(Namespace:="http://wesnetdesigns.org/ImageProcessor")> _
    <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
    <ScriptService()> _
    Public Class ImageProcessor
        Inherits System.Web.Services.WebService

        Private _CacheTime As TimeSpan = TimeSpan.FromSeconds(120.0#)
        Private _CachePersistence As CachePersistenceType = Defaults.CachePersistenceType
        Private _CacheKey As String
        Private _CacheFolderpath As String
        Private _Image As System.Drawing.Bitmap
        Private _ImageSize As System.Drawing.Size
        Private _Rect As System.Drawing.Rectangle

        <WebMethod(), ScriptMethod()> _
        Public Function ProcessImage(ByVal Operation As String, ByVal CacheFolderpath As String, ByVal CacheKey As String, ByVal Rect As Rectangle) As ProcessImageResult
            Dim _Command As String = ""

            If String.IsNullOrEmpty(CacheFolderpath) Then
                _CachePersistence = CachePersistenceType.Memory
            Else
                _CacheFolderpath = Server.UrlDecode(CacheFolderpath)
                _CachePersistence = CachePersistenceType.File
            End If

            If String.IsNullOrEmpty(CacheKey) Then
                Throw New ArgumentNullException("CacheKey cannot be null or empty")
            Else
                _CacheKey = CacheKey
            End If

            If Image Is Nothing Then
                Select Case _CachePersistence
                    Case CachePersistenceType.Memory
                        Throw New InvalidOperationException("Cached image data with key of " & CacheKey & " has expired.")
                    Case CachePersistenceType.File
                        Throw New InvalidOperationException("Cached image file " & CacheKey & ".resource not found.")
                End Select
            End If

            If Rect.IsEmpty Then
                _Rect = New Rectangle(0, 0, _ImageSize.Width, _ImageSize.Height)
            Else
                _Rect = Rect
            End If

            Dim img As System.Drawing.Bitmap

            If Operation = "Crop" Then
                img = New Bitmap(_Rect.Width, _Rect.Height)
                Dim g As Graphics = Graphics.FromImage(img)
                g.DrawImage(Image, New Rectangle(0, 0, _Rect.Width, _Rect.Height), _Rect, GraphicsUnit.Pixel)
                g.Dispose()
                _Command = "Reset"
            Else
                img = New Bitmap(Image)
                Select Case Operation
                    Case "RotateLeft"
                        ImageUtils.Rotate(img, RotateFlipType.Rotate270FlipNone)
                        _Command = "Reset"
                    Case "RotateRight"
                        ImageUtils.Rotate(img, RotateFlipType.Rotate90FlipNone)
                        _Command = "Reset"
                    Case "FlipHoriz"
                        ImageUtils.Rotate(img, RotateFlipType.RotateNoneFlipX)
                    Case "FlipVert"
                        ImageUtils.Rotate(img, RotateFlipType.RotateNoneFlipY)
                    Case "Lighten"
                        ImageUtils.AdjustBrightness(img, 5)
                    Case "Darken"
                        ImageUtils.AdjustBrightness(img, -5)
                    Case "ContrastUp"
                        ImageUtils.AdjustContrast(img, 8)
                    Case "ContrastDown"
                        ImageUtils.AdjustContrast(img, -3)
                    Case "SaturationUp"
                        ImageUtils.AdjustSaturation(img, 5)
                    Case "SaturationDown"
                        ImageUtils.AdjustSaturation(img, -5)
                    Case Else
                        Throw New ArgumentException("Operation " & Operation & " is not recognized.")
                End Select
            End If
            If Not img Is Nothing Then
                img.Tag = True      'Tag property is used to denote image has changed (IsDirty)
                Image = img
            End If
            Return New ProcessImageResult(_Command, _ImageSize, IsDirty)
        End Function

        Private Property Image() As System.Drawing.Bitmap
            Get
                If _Image Is Nothing Then
                    _Image = GetCachedImage()
                End If
                Return _Image
            End Get
            Set(ByVal value As System.Drawing.Bitmap)
                If value Is Nothing Then
                    InvalidateImageCache()
                    _ImageSize = Size.Empty
                Else
                    SetCachedImage(value)
                End If
                _Image = value
            End Set
        End Property

        Public ReadOnly Property IsDirty() As Boolean
            Get
                Return Not ((Image Is Nothing) OrElse (Convert.ToBoolean(Image.Tag) = False))
            End Get
        End Property

        Private Sub InvalidateImageCache()
            Select Case _CachePersistence
                Case CachePersistenceType.Memory
                    HttpRuntime.Cache.Remove(_CacheKey)
                Case CachePersistenceType.File
                    RemoveCachedImage()
            End Select
        End Sub

        Private Function GetCacheFileName() As String
            If String.IsNullOrEmpty(_CacheKey) Then
                Throw New System.ArgumentNullException("CacheKey", "Cache key cannot be null or empty")
            End If
            If String.IsNullOrEmpty(_CacheFolderpath) Then
                Throw New System.IO.IOException("Cache folder path cannot be null or empty")
            End If
            'Dim fileNameBytes As Byte() = ASCIIEncoding.ASCII.GetBytes(CacheKey)
            'Dim Base64Filename As String = Convert.ToBase64String(fileNameBytes).Replace("/", "-")
            Dim CacheFilename As String = Path.Combine(_CacheFolderpath, _CacheKey & ".resource").Replace("\", "/")
            Return CacheFilename
        End Function

        Private Sub DeleteCacheFile(ByVal Filename As String)
            If Not String.IsNullOrEmpty(Filename) Then File.Delete(Filename)
        End Sub

        Private Sub RemoveCachedImage()
            Dim Filename As String = GetCacheFileName()
            DeleteCacheFile(Filename)
        End Sub

        Private Function GetCachedImage() As System.Drawing.Bitmap
            Dim obj As Object = Nothing
            Dim s As FileStream = Nothing
            Dim img As System.Drawing.Bitmap = Nothing
            Select Case _CachePersistence
                Case CachePersistenceType.Memory
                    obj = HttpRuntime.Cache(_CacheKey)
                Case CachePersistenceType.File
                    Dim CacheFilepath As String = GetCacheFileName()
                    If File.Exists(CacheFilepath) Then
                        Try
                            s = File.OpenRead(CacheFilepath)
                            obj = New Bitmap(s)
                        Catch ex As Exception
                            DeleteCacheFile(CacheFilepath)
                        Finally
                            If Not s Is Nothing Then s.Close()
                        End Try
                    End If
            End Select
            If Not obj Is Nothing Then
                img = CType(obj, System.Drawing.Bitmap)
                _ImageSize = New Size(img.Width, img.Height)
            End If
            Return img
        End Function

        Private Sub SetCachedImage(ByVal img As System.Drawing.Bitmap)
            If img Is Nothing Then Exit Sub
            Select Case _CachePersistence
                Case CachePersistenceType.Memory
                    HttpRuntime.Cache.Insert(_CacheKey, img, Nothing, DateTime.MaxValue, _CacheTime, Caching.CacheItemPriority.AboveNormal, Nothing)
                Case CachePersistenceType.File
                    Dim CacheFilepath As String = GetCacheFileName()
                    If File.Exists(CacheFilepath) Then
                        File.Delete(CacheFilepath)
                    End If
                    img.Save(CacheFilepath)
            End Select
            _ImageSize = New Size(img.Width, img.Height)
        End Sub
    End Class
End Namespace
